package tue.cse.advanceddatabases.project;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import java.util.logging.Logger;

import javax.faces.context.FacesContext;

import org.dom4j.Element;

import tue.cse.advanceddatabases.project.db.comment.Comment;
import tue.cse.advanceddatabases.project.db.comment.CommentsParser;

public class CommentsManagerBean extends MusicEngineBean {
	
	private static final String COMMENT_TYPE_ALBUM = "ALBUM";
	private static final String COMMENT_TYPE_ARTIST = "ARTIST";
	private static final String COMMENT_TYPE_TRACK = "TRACK";
	
	private Logger logger = Logger.getLogger(CommentsManagerBean.class.getName());
	private String text;

	LoginManager loginManagerBean;
	
	public LoginManager getLoginManagerBean() {
		return loginManagerBean;
	}
	public void setLoginManagerBean(LoginManager loginManagerBean) {
		this.loginManagerBean = loginManagerBean;
	}

	public String getText() {
		return text;
	}
	public void setText(String text) {
		this.text = text;
	}
	
	/*
	 * public methods (actions)
	 */
	
	public void insertAlbumComment(){
		
		logger.info("Inserting Album Comment");
		insertComment(COMMENT_TYPE_ALBUM);
		updateAlbumComment();
	}
	
	public void insertTrackComment(){
		
		logger.info("Inserting Track Comment");
		insertComment(COMMENT_TYPE_TRACK);
		updateTrackComment();
	}
	
	public void insertArtistComment(){
		
		logger.info("Inserting Artist Comment");
		insertComment(COMMENT_TYPE_ARTIST);
		updateArtistComment();
	}
	
	public void insertComment(String aCommentType){
		
		logger.info("Inserting Comment");
		
		if (getText() == null || getText().trim().length() == 0){
			logger.info("Comment Text is empty.");	
			return;
		}
				  
		String commentType = aCommentType;
		String musicId = getMusicId();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String date = sdf.format(new Date());
		
		//TODO: generate  commentId 
		String commentId = date;
		
		String command = getInsertCommentCommand(commentId, commentType, musicId, date, getText(), 
				loginManagerBean.getLoginId());
		
		String query = updateBegin() + command + updateEnd();
		String result = executeQuery(query,"Comments.xml");
		
		logger.info("Inserting result is:" + result);
		
		setText(null);
	}
	
	/** update album comment **/
	private void updateAlbumComment() {
		String musicId = getMusicId();

		// Update Rating value
		String command = getUpdateAlbumCommentQuery(musicId);
		String query = queryBegin() + command + queryEnd();
		String result = executeQuery(query,"Albums.xml");	
		logger.info("updateAlbumComment result is:" + result);

	}
	
	/** update artist comment **/
	private void updateArtistComment() {
		String musicId = getMusicId();

		// Update Rating value
		String command = getUpdateArtistCommentQuery(musicId);
		String query = queryBegin() + command + queryEnd();
		String result = executeQuery(query,"Artists.xml");	
		logger.info("updateArtistComment result is:" + result);
	}
	
	/** update track comment **/
	private void updateTrackComment() {
		String musicId = getMusicId();

		// Update Rating value
		String command = getUpdateTrackCommentQuery(musicId);
		String query = queryBegin() + command + queryEnd();
		String result = executeQuery(query,"Tracks.xml");	
		logger.info("updateTrackComment result is:" + result);
	}	
	
	/** remove Comment by "commentKey" parameter **/
	public void removeComment(){
		logger.info("Deleting Comment"); 	
	     
	  	String command = getDeleteCommentCommand(getCommentKey());
    		
	  	String query = updateBegin() + command + updateEnd();
	  	String result = executeQuery(query, "Comments.xml");
    		
	  	logger.info("Deleting result is:" + result);
    		
	  	if ("fail".equalsIgnoreCase(result)){
	  	  	return;
	  	}
	}
	
	/** remove all Comments by "commentMusicId" parameter **/
	public void removeAllComments(){
	  	logger.info("Deleting All Comments"); 	
	     
	  	String command = getDeleteAllCommentsCommand(getMusicId());
    		
	  	String query = updateBegin() + command + updateEnd();
	  	String result = executeQuery(query, "Comments.xml");
    		
	  	logger.info("Deleting result is:" + result);
    		
	  	if ("fail".equalsIgnoreCase(result)){
	  	  	return;
	  	}
	}
	
	/** return the album comments **/
	public List<Comment> getAlbumComments(){
		
		logger.info("Searching comments by Album ID:");
		
		String musicId = getAlbumKey();		
		
		String comments = searchCommentsByMusicId(musicId);
		
		logger.info("Results found \n" + comments);
		
		if (comments != null){
			List<Element> commentsElement = removeExistDBElement(comments);
			if (commentsElement!=null){
				logger.info("Tracks are contained in" + commentsElement);
				return CommentsParser.parse(commentsElement);
			}
		}
		
		return null;		
	}
	
	/** return the artist comments **/
	public List<Comment> getArtistComments(){
		
		logger.info("Searching comments by Artist ID:");
		
		String musicId = getArtistKey();		
		
		String comments = searchCommentsByMusicId(musicId);
		
		logger.info("Results found \n" + comments);
		
		if (comments != null){
			List<Element> commentsElement = removeExistDBElement(comments);
			if (commentsElement!=null){
				logger.info("Tracks are contained in" + commentsElement);
				return CommentsParser.parse(commentsElement);
			}
		}
		
		return null;		
	}
	
	/** return the artist comments **/
	public List<Comment> getTrackComments(){
		
		logger.info("Searching comments by Tracl ID:");
		
		String musicId = getTrackKey();		
		
		String comments = searchCommentsByMusicId(musicId);
		
		logger.info("Results found \n" + comments);
		
		if (comments != null){
			List<Element> commentsElement = removeExistDBElement(comments);
			if (commentsElement!=null){
				logger.info("Tracks are contained in" + commentsElement);
				return CommentsParser.parse(commentsElement);
			}
		}
		
		return null;		
	}
	
	
	
	public List<String> getRatings(){
		Vector<String> ratings = new Vector<String>();
		ratings.add("1");
		ratings.add("2");
		ratings.add("3");
		ratings.add("4");
		ratings.add("5");
		return ratings;
	}
	
	//GORAN
	/** return the music item comments **/
	public List<Comment> getComments(){
		
		logger.info("Searching comments by Music ID:");		
		
		String comments = searchCommentsByMusicId(getMusicId());
		
		logger.info("Results found \n" + comments);
		
		if (comments != null){
			List<Element> commentsElement = removeExistDBElement(comments);
			if (commentsElement!=null){
				logger.info("Music items are contained in" + commentsElement);
				return CommentsParser.parse(commentsElement);
			}
		}
		
		return null;		
	}
	
	/*
	 * private methods
	 */
	
	/** get the comment music id of the request parameters **/
	private String getMusicId() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		return (String) facesContext.getExternalContext().getRequestParameterMap().get("commentMusicId");
	}
	/** get the comment type of the request parameters **/
	private String getCommentType() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		return (String) facesContext.getExternalContext().getRequestParameterMap().get("commentType");

	}
	/** get the comment key of the request parameters **/
	private String getCommentKey() {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		return (String) facesContext.getExternalContext().getRequestParameterMap().get("commentKey");
	}
	
	private String searchCommentsByMusicId(String musicId){
		logger.info("Searching Comments by Album ID:" + musicId);

		String query = queryBegin() + commentsMusicIdQuery(musicId) + queryEnd();
		String result = executeQuery(query,"Comments.xml");
		
		if (!("fail".equalsIgnoreCase(result)))
			return result;

		return null;		
	}
	
	/*
	 * Queries
	 */
	
	/** insert comment command **/
	private String getInsertCommentCommand(String commentId, String type, String musicId, String date, 
			String comment, String userId){
		return "<xu:append select=\"/comments\">" + 
				"<xu:element name=\"comment\">" +
				"<id>" + commentId + "</id>" +
				"<type>" + type + "</type>" +
				"<music_id>" + musicId + "</music_id>" +
				"<text>" + comment + "</text>" +
				"<user_id>" + userId + "</user_id>" +
				"<date>" + date + "</date>" +
				"</xu:element></xu:append>";
	}
	
	/** delete comment command **/
	private String getDeleteCommentCommand(String commentId){
		return "<xu:remove select=\"/comments/comment[id = \'" + commentId + "\']\"/>";
	}	
	
	/** delete all comments command **/
	private String getDeleteAllCommentsCommand(String commentMusictId){
		return "<xu:remove select=\"/comments/comment[music_id = \'" + commentMusictId + "\']\" />";
	}
	
	/** tracks by album-id query **/
	private String commentsMusicIdQuery(String musicId){
		return "element { \"comments\" }{ " +
			"for $comment in //comment " +
			"where $comment/music_id/text() = \"" + musicId + "\" " + 
			"return $comment" +
			"}";
	}
	
	/** update album comment command **/
	private String getUpdateAlbumCommentQuery(String albumId) {
		return "for $album in //album[@id='" + albumId + "'] " +
				" let $newComment :=  fn:number($album/comment-count) + 1" +
				" return " +
				" update replace $album/comment-count with " + 
				" element { \"comment-count\" }{ $newComment }";
	}
	
	/** update artist comment command **/
	private String getUpdateArtistCommentQuery(String artistId) {
		return "for $artist in //artist[@id='" + artistId + "'] " +
				" let $newComment :=  fn:number($artist/comment-count) + 1" +
				" return " +
				" update replace $artist/comment-count with " + 
				" element { \"comment-count\" }{ $newComment }";
	}
	
	/** update track comment command **/
	private String getUpdateTrackCommentQuery(String trackId) {
		return "for $track in //track[@id='" + trackId + "'] " +
				" let $newComment :=  fn:number($track/comment-count) + 1" +
				" return " +
				" update replace $track/comment-count with " + 
				" element { \"comment-count\" }{ $newComment }";
	}

}
